
import os
import django
# 设置 DJANGO_SETTINGS_MODULE 环境变量（引入settings文件）
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ROOT.settings')
# 加载 Django 项目配置
django.setup()

import os
import numpy as np
from tensorflow.keras.applications import ResNet50, ResNet101
from tensorflow.keras.applications.resnet50 import preprocess_input
from tensorflow.keras.applications.resnet import preprocess_input  # 注意：ResNet101 的预处理模块
from tensorflow.keras.preprocessing import image
from sklearn.metrics.pairwise import cosine_similarity
from multiprocessing import Process, Queue

import time
from datetime import datetime
from threading import Thread
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from django.forms.models import model_to_dict
from apps.ipo.models import IpoImage, Feature, JSTOpenImage

# """ 独立进程导入模型 """
# from django.apps import apps
# Feature = apps.get_model('ipo', 'Feature')
# JSTOpenImage = apps.get_model('ipo', 'JSTOpenImage')

# Create your views here.


class IpoResNet:

    def __init__(self, model, db_data, target_image, pool_image):
        self.net50 = 'ResNet50'
        self.net101 = 'ResNet101'
        self.models = model
        print(f'子进程机器学习 - {self.models }模型：{os.getpid()}')
        if self.models == self.net101:
            self.model = ResNet101(weights='imagenet', include_top=False, pooling='avg')
        if self.models == self.net50:
            self.model = ResNet50(weights='imagenet', include_top=False, pooling='avg')

        start_time = datetime.now()
        image, sim = self.main(target_image, pool_image)
        end_time = datetime.now()
        s = end_time - start_time
        total_seconds = s.total_seconds() # 耗时(秒)
        self.db_update(db_data, image, sim, total_seconds)

    def db_update(self, _db_data, _image, _sim, _consuming):
        obj = IpoImage.objects.filter(**_db_data).first()

        if self.models == self.net101:
            obj.name_net101 = _db_data['image_name']
            obj.number_net101 = _image.split('/')[-1].split('.')[0]
            obj.jst_paths_net101 = f"{settings.MEDIA_URL}{_image.split('/')[-1]}"
            obj.net101_sim = _sim
            obj.time_net101_consuming = _consuming

        if self.models == self.net50:
            obj.name_net50 = _db_data['image_name']
            obj.number_net50 = _image.split('/')[-1].split('.')[0]
            obj.jst_paths_net50 = f"{settings.MEDIA_URL}{_image.split('/')[-1]}"
            obj.net50_sim = _sim
            obj.time_net50_consuming = _consuming

        # obj.paths = f"{settings.MEDIA_URL}{_image.split('/')[-1]}"    # 字段废除
        obj.save()

    def extract_features(self, img_path):
        """
        提取图像的特征向量
        """
        img = image.load_img(img_path, target_size=(224, 224))  # ResNet 输入尺寸为 224x224
        img_data = image.img_to_array(img)
        img_data = np.expand_dims(img_data, axis=0)
        img_data = preprocess_input(img_data)  # 使用 ResNet 的预处理函数
        features = self.model.predict(img_data)
        return features.flatten()

    @staticmethod
    def find_most_similar(target_features, image_features_list):
        """
        找到与目标特征最相似的图片
        """
        similarities = []
        for features in image_features_list:
            similarity = cosine_similarity([target_features], [features])[0][0]
            similarities.append(similarity)
        most_similar_index = np.argmax(similarities)
        return most_similar_index, similarities

    def main(self, _target_image, _images):
        # 提取目标图片特征
        target_features = self.extract_features(_target_image)

        # 提取图片池中所有图片的特征
        image_features_list = Feature.objects.get(model=self.models).features

        # 找到最相似的图片
        most_similar_index, similarities = self.find_most_similar(target_features, image_features_list)

        # 输出结果
        # image_name = _target_image.split('\\')[-1]
        # return f"与{image_name}最相似的图片是: {_images[most_similar_index]}, 相似度: {similarities[most_similar_index] * 100:.2f}%"
        return _images[most_similar_index], f"{similarities[most_similar_index] * 100:.2f}%"


class IpoImages(APIView):

    def post(self, request):

        datas = list()
        for item in request.data['images']:
            datas.append({
                'paths': f"{settings.MEDIA_ROOT}{settings.UPLOAD_PATH}{item.split('/')[-1]}",
                'db_data': {
                    'username': request.user.username,
                    'image_name': f"{settings.MEDIA_URL}{settings.UPLOAD_PATH[1:]}{item.split('/')[-1]}",
                }
            })
        # 本地图像路径
        target_image_paths = [f'{settings.MEDIA_ROOT}/{item["paths"].split("/")[-1]}' for item in JSTOpenImage.objects.all().values('paths')]

        """ 
        效率提升方案 
        1、每日定时更新图片特征库
        2、找到最相似图片使用并行多进程
        """
        for data in datas:
            IpoImage.objects.get_or_create(**data['db_data'])

            for item in ['ResNet101', 'ResNet50']:
                p = Process(target=IpoResNet, args=(item, data['db_data'], data['paths'], target_image_paths))
                p.start()

        return Response({'code': 200, 'msg': '后台对比中'})


class IpoAccuracy(APIView):

    def post(self, request):
        IpoImage.objects.filter(id=request.data['id']).update(accuracy=request.data['text'])
        return Response({'code': 200, 'msg': '感谢您的反馈.', 'data': {}})
